/*
 * uart.cpp
 *
 *  Created on: Dec 21, 2018
 *      Author: zhan
 */

#include "uart.h"


Uart::Callback *usart1_received_callback = NULL;
Uart::Callback *usart2_received_callback = NULL;
Uart::Callback *usart3_received_callback = NULL;
Uart::Callback *uart4_received_callback = NULL;
Uart::Callback *uart5_received_callback = NULL;
Uart::Callback *usart6_received_callback = NULL;

typedef struct {
	USART_TypeDef *uartx;
	IRQn_Type irq_type;
	uint8_t gpio_af;
	Uart::Callback **callback;
}uart_info_t;

static const uart_info_t uart_infos[] = {
		{USART1, USART1_IRQn, GPIO_AF_USART1, &usart1_received_callback},
		{USART2, USART2_IRQn, GPIO_AF_USART2, &usart2_received_callback},
		{USART3, USART3_IRQn, GPIO_AF_USART3, &usart3_received_callback},
		{UART4,  UART4_IRQn,  GPIO_AF_UART4,  &uart4_received_callback },
		{UART5,  UART5_IRQn,  GPIO_AF_UART5,  &uart5_received_callback },
		{USART6, USART6_IRQn, GPIO_AF_USART6, &usart6_received_callback},
};

static uart_info_t *get_uarts_info(USART_TypeDef *x)
{
	for(size_t i=0;i<sizeof(uart_infos)/sizeof(uart_info_t);i++){
		if (x == uart_infos[i].uartx){
			return (uart_info_t *)&uart_infos[i];
		}
	}
	return NULL;
}



Uart::Uart(USART_TypeDef *x, GpioPin *tx, GpioPin *rx, uint32_t baud_rate/*=115200*/,
		uint16_t hardware_flow_control/*=USART_HardwareFlowControl_None*/,
		uint16_t mode/*=USART_Mode_Rx|USART_Mode_Tx*/,
		uint16_t parity/*=USART_Parity_No*/,
		uint16_t stop_bits/*=USART_StopBits_1*/,
		uint16_t word_length/*=USART_WordLength_8b*/)
{
	on_received_callback = NULL;
	uartx = x;
	this->tx = tx;
	this->rx = rx;
	init_stru.USART_BaudRate = baud_rate;
	init_stru.USART_HardwareFlowControl = hardware_flow_control;
	init_stru.USART_Mode = mode;
	init_stru.USART_Parity = parity;
	init_stru.USART_StopBits = stop_bits;
	init_stru.USART_WordLength = word_length;
}

void Uart::write(uint8_t *buf, int len)
{
	for (int i = 0; i < len; i++) {
		USART_SendData(uartx, buf[i]);
		while (RESET == USART_GetFlagStatus(uartx, USART_FLAG_TXE));
	}
}


void Uart::set_on_received_callback(Callback *callback)
{
	uart_info_t *info = get_uarts_info(uartx);
	*(info->callback) = callback;
}


bool Uart::init(void)
{
	tx->init(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_OD, GPIO_PuPd_UP);
	rx->init(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_OD, GPIO_PuPd_UP);

	uart_info_t *info = get_uarts_info(uartx);
	GPIO_PinAFConfig(rx->gpiox, GpioPin::get_pin_source(rx->pin), info->gpio_af);
	GPIO_PinAFConfig(tx->gpiox, GpioPin::get_pin_source(tx->pin), info->gpio_af);

	USART_Init(uartx, &init_stru);
	USART_ClearFlag(uartx, USART_FLAG_RXNE | USART_FLAG_TC);
	enable_module();
	return true;
}


void USART1_IRQHandler(void)
{
	if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
		uint16_t c = USART_ReceiveData(USART1);
		if ( usart1_received_callback != NULL ){
			usart1_received_callback->callback(c);
		}
	}
}

void USART2_IRQHandler(void)
{
	if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET) {
		uint16_t c = USART_ReceiveData(USART2);
		if ( usart2_received_callback != NULL ){
			usart2_received_callback->callback(c);
		}
	}
}

void USART3_IRQHandler(void)
{
	if (USART_GetFlagStatus(USART3, USART_FLAG_RXNE) == SET) {
		uint16_t c = USART_ReceiveData(USART3);
		if ( usart3_received_callback != NULL ){
			usart3_received_callback->callback(c);
		}
	}
}

void UART4_IRQHandler(void)
{
	if (USART_GetFlagStatus(UART4, USART_FLAG_RXNE) == SET) {
		uint16_t c = USART_ReceiveData(UART4);
		if ( uart4_received_callback != NULL ){
			uart4_received_callback->callback(c);
		}
	}
}

void UART5_IRQHandler(void)
{
	if (USART_GetFlagStatus(UART5, USART_FLAG_RXNE) == SET) {
		uint16_t c = USART_ReceiveData(UART5);
		if ( uart5_received_callback != NULL ){
			uart5_received_callback->callback(c);
		}
	}
}


void USART6_IRQHandler(void)
{
	if (USART_GetFlagStatus(USART6, USART_FLAG_RXNE) == SET) {
		uint16_t c = USART_ReceiveData(USART6);
		if ( usart6_received_callback != NULL ){
			usart6_received_callback->callback(c);
		}
	}
}

